home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
007
/
vtkerma1.arc
/
MSHELPER.ASM
< prev
next >
Wrap
Assembly Source File
|
1986-02-13
|
19KB
|
772 lines
PAGE 59, 132
TITLE MsHelper -- Windowing help module for VT100 emulation on IBM PC
; Update 6 Jan 86
IF1
%OUT >> Starting pass 1
ELSE
%OUT >> Starting pass 2
ENDIF
PUBLIC Helper
.SALL
;***************************************************************************
; *Definitions* ...
; Global defs
INCLUDE MsDefs.H
DataS SEGMENT PUBLIC 'DataS'
EXTRN Which_page:BYTE, Screen_flags:BYTE
EXTRN Video_page_addresses:WORD, m7171:BYTE
EXTRN Force_mono:BYTE, m7171:BYTE
Screen EQU 10h ; BIOS screen call
Kb EQU 16h ; BIOS keyboard call
Old_7171_mode DB ? ; If we were here before, which mode was it?
; Screen stuff
Number_of_columns EQU 80 ; Width in characters
Number_of_rows_PC EQU 25 ; Length in rows including mode line
Number_of_chars_on_PC_screen EQU Number_of_columns*Number_of_rows_PC
; Number of chars in IBM screen
; Flag set in Screen_flags
Screen_changed EQU 8 ; Data on more than one line changed
Saved_mode_line DW Number_of_columns DUP (?) ; Saved image of Mode line
; Scan codes for keys we have predefined ...
Escape_key EQU 1
Space_key EQU 57
F6_key EQU 64
ALT_F6_key EQU 109
End_key EQU 79
Down_key EQU 80
PgDn_key EQU 81
Left_key EQU 75
Right_key EQU 77
Home_key EQU 71
Up_key EQU 72
PgUp_key EQU 73
Characters LABEL BYTE
DB Space_key, Escape_key, F6_key
DB Home_key, End_key, PgUp_key
DB PgDn_key, Up_key, Down_key
DB Left_key, Right_key, ALT_F6_key
N_Characters EQU $-Characters
Actions LABEL WORD
DW CHK_bye, CHK_bye, CHK_bye
DW Do_Home, Do_End, Do_PgUp
DW Do_PgDn, Do_Up, Do_Down
DW Do_Up, Do_Down, CHK_bye
DW Do_boop
PUBLIC Help_file_name, Characters, Actions
Help_file_name LABEL BYTE
Program_name
DB '.HLP',0 ; Name of our help file
Help_file_7171 LABEL BYTE
Program_name
DB '.H71',0 ; Name of our help file on IBM 7171
No_memory DB ' *** Not enough memory for HELP -- Press any key to continue ***$'
Cant_find_file DB ' ***** Missing '
Program_name
DB '.HLP -- Press any key to continue *****$'
Cant_find_7171 DB ' ***** Missing '
Program_name
DB '.H71 -- Press any key to continue *****$'
DataS ENDS
; Dummy segment for allocated memory
HAlloc SEGMENT AT 0
First_line DW ? ; Ptr to first line in database
Last_line DW ? ; Ptr to last line in database
Last_top_line DW ? ; Ptr to line on top of last frame
Current_line DW ? ; Ptr to line currently at top of window
Which_row DW ? ; Which row are we writing in?
PUBLIC Our_Image, Our_cursor, Which_row, Current_line, First_line
Our_cursor DW ? ; Our position
Our_Image DW Number_of_chars_on_PC_screen DUP (?) ; Our buffer
PUBLIC Help_database, Help_file_buffer,End_HAlloc
Zero DB ? ; Make backward searches stop here ...
Help_database DB 300*74 DUP (?) ; Where we store the help text
Help_file_buffer DB 2048 DUP (?) ; Buffer for reading Help file from disk
End_HAlloc LABEL BYTE ; Ptr to end of what we need
HAlloc ENDS
Code SEGMENT PUBLIC
EXTRN Put_Screen:NEAR, Get_Screen_Segment:NEAR, Boop:NEAR
EXTRN SPath:NEAR, Check_table:NEAR, Do_mode_line:NEAR
EXTRN Get_memory_block:NEAR, PutErr_PC:NEAR, Screen_Image_ptr:DWORD
EXTRN Which_card:BYTE, Mode_line_ptr:DWORD
ASSUME CS:Code, DS:DataS, ES:DataS
Normal_ds DW ? ; Ptr back to ds on entry
HAlloc_ptr DW ? ; Address of HAlloc segment
PUBLIC HFlags
HFlags DB 0 ; Internal flags, kept in code segment
; for easy access
Bye_bye EQU 1 ; Flag to leave
Been_here EQU 2 ; Already did once-only initialization
Helper PROC
and HFlags, NOT Bye_bye ; Flag that we aren't leaving yet
test HFlags, Been_here ; Been here before?
jz HLP_go ; No ...
; We have been here before, but maybe with the wrong help file ...
mov al, m7171 ; Pick up current 7171 mode
cmp al, Old_7171_mode ; Same as last time?
je HLP_1 ; Same, just display our buffer
; We have been here before, so we already have memory allocated ...
; We just need to reload the database
mov ax, HAlloc_ptr ; Reuse old memory
jmp SHORT H_ok ; Join common code
HLP_go:
; First, get some memory to work in
; *** The silly assembler won't let me do this, saying
; Constant was expected
; or something like that ...
; mov bx, (OFFSET End_HAlloc+15) SHR 4 ; Lowest location we don't use,
; round up to next higher paragraph,
; then convert to number of paragraphs
mov bx, OFFSET End_HAlloc+15 ; Round up to next paragraph
mov cl, 4 ; Shift count
shr bx, cl ; Shift to get number of paras we need
call Get_memory_block ; Get a memory block of the right size
jnc H_OK ; Ok so far ...
mov dx, OFFSET No_memory ; Complain
jmp Do_mode_line_error ; Display noisy error message, wait for
; keystroke, then exit, restoring
; clobbered mode line
H_OK: mov HAlloc_ptr, ax ; Save the address of our block
mov bx, ds ; Set up ptr back to ds
mov Normal_ds, bx ; Save ptr back to old one
; Switch to HAlloc segment ...
mov ds, ax ; Point ds to HAlloc
mov es, ax ; es also ...
ASSUME ds:HAlloc, es:HAlloc ; Tell assembler we have a new ds and es
mov Zero, 0 ; Store a zero
call Build_Help_database ; Build the database
test HFlags, Bye_bye ; Time to leave?
jz HLP_0 ; Not yet
; *** Properly speaking, we really ought to release the memory we
; were just allocated, since we can't use it ... maybe later ***
jmp Back_to_normal_ds ; Oh well ...
HLP_0: or HFlags, Been_here ; Flag for later
call Back_to_normal_ds
ASSUME ds:DataS, es:DataS
mov al, m7171 ; Pick up current 7171 mode
mov Old_7171_mode, al ; Store it for later test
call Use_our_own_ds
ASSUME ds:HAlloc, es:HAlloc
jmp SHORT HLP_1a
ASSUME ds:DataS, es:DataS
HLP_1: call Use_our_own_ds ; Switch to HAlloc segment
ASSUME ds:HAlloc, es:HAlloc
HLP_1a: call Build_box ; Build outline / background for Help window
mov ax, First_line ; Address of start at Help text
mov Current_line, ax ; Set up as current position
HLP_2: call Fill_frame ; Get frame ready
call Do_the_screen ; Display this frame
call Check_keystrokes ; See what to do next
test HFlags, Bye_bye ; Time to leave?
jz HLP_2 ; No, go update the frame
jmp Back_to_normal_ds ; Done here
PUBLIC Bombed
ASSUME ds:DataS, es:DataS
Bombed: call Boop ; Bombed, make a noise
or HFlags, Bye_bye ; Go home
ret
ASSUME ds:HAlloc, es:HAlloc
PUBLIC Build_Help_database
Build_Help_database:
call Back_to_normal_ds ; Need old ds to open file
ASSUME ds:DataS, es:DataS
mov ax, OFFSET Help_file_name ; Name of file to get
cmp m7171, 0 ; In 7171 mode?
je BUI_0
mov ax, OFFSET Help_file_7171 ; Name of the other file
BUI_0: call spath ; Search path for file, DSK: first
jnc BUI_ok ; Got it, go work with it
mov dx, OFFSET Cant_find_file ; Complain
cmp m7171, 0 ; In 7171 mode?
je BUI_1
mov dx, OFFSET Cant_find_7171 ; Complain about missing 7171 file
BUI_1: call Do_mode_line_error ; Wait for a key
jmp Use_our_own_ds ; Reset ds and return NG
BUI_ok:
mov dx, ax ; Copy ptr to name to dx
mov ax, (Open2*100h) + 0 ; Open file for input
int DOS ; Try to open the file
jc Bombed ; Huh?
mov bx, ax ; Copy handle to bx
call Use_our_own_ds ; Back to our own version
ASSUME ds:HAlloc, es:HAlloc
mov di, OFFSET Help_database ; Ptr to start of our database
mov First_line, di ; Save ptr to start for later
mov Current_line, di ; Also a ptr for making Last_line later
cld ; Build forwards
BUI_disk_read:
mov ah, ReadF2 ; Code to read from file, handle still in bx
mov cx, SIZE Help_file_buffer ; Number of characters to try for
mov dx, OFFSET Help_file_buffer ; Where to put them
int DOS ; Read from the help file
jc BUI_finish ; Stop on error
or ax, ax ; Check for zero bytes read
jz BUI_finish ; Hit EOF, go finish it up
mov cx, ax ; Byte count for this record
inc cx ; We decr once too many times
mov si, OFFSET Help_file_buffer ; Ptr to buffer
BUI_lp: loop BUI_next_char ; If more chars, go get one
jmp SHORT BUI_disk_read ; Buffer is empty, try to refill it
BUI_next_char:
lodsb ; Get the next byte
cmp al, CtlZ ; Control-Z?
jl BUI_control ; Less, check for control char
je BUI_lp ; Ignore control Z
stosb ; Store the char
jmp BUI_lp ; Go do another one
BUI_control:
cmp al, Lf ; Line feed?
jne BUI_lp ; No
sub al, al ; Make a zero
stosb ; Tie off the last line
mov ax, Current_line ; Pick up trailing ptr
mov Last_line, ax ; Assume it's the last line, for now
mov Current_line, di ; Update trailing ptr for next round
jmp BUI_lp ; Go get another character
BUI_finish:
sub al, al ; Make a zero
mov cx, 25 ; Make several blank lines after help database
rep stosb ; Write a string of zeros
mov ah, 3eh ; Code to close a file
int DOS ; Close the file
mov di, Last_line
mov Current_line, di
mov cx, Len - 3 ; Maximum number of lines to move
call PgUp_lp ; Get a new DI pointing to proper line
mov Last_top_line, di ; Save for later
ret ; Done here
PUBLIC Build_box
Build_box:
cld ; Forwards
mov di, OFFSET Our_Image ; Our own buffer
mov cx, Number_of_chars_on_PC_screen ; How many chars
lds si, Screen_Image_ptr ; Addr of copy of screen at entry
rep movsw ; Install incoming screen as background
push es ; Our segment
pop ds ; Set up ds again
Wid=Number_of_columns-(2*Help_window_left) ; How many columns
Len=Number_of_rows_PC-(2*Help_window_top) ; How many rows
Color_attr=1eh ; Bright yellow on blue
Mono_attr=70h ; Black on white
%OUT >> About half way through source file
Upper_left=218 ; Box drawing chars
Upper_right=191
Lower_left=192
Lower_right=217
Horizontal=196
Vertical=179
mov ax, Help_window_top ; Row number of top of window
mov Which_row, ax ; Save it for later
call Make_new_ptr ; Get a new DI
; Set up proper attribute based on card type
mov bh, Mono_attr ; Assume mono
call Back_to_normal_ds
ASSUME ds:DataS, es:DATAS
cmp Force_mono, 0 ; Are we stuck with mono?
jne MON_0 ; Yes
call Get_Screen_Segment
cmp ax, 0b000h ; Mono?
je MON_0 ; It is, go use it
mov bh, Color_attr ; Color, use it instead
PUBLIC MON_0
MON_0: mov ah, bh ; Install in ah
call Use_our_own_ds
ASSUME ds:HAlloc, es:HAlloc
; Do top row of help window
mov al, Upper_left
stosw
mov al, Horizontal
mov cx, Wid - 2
rep stosw
mov al, Upper_right
stosw
inc Which_row ; Bump to next row
call Make_new_ptr ; Point to it
; Do the middle rows of the help window
mov cx, Len - 2 ; Number of rows to do
PUBLIC LP_1
LP_1: push cx
mov al, Vertical
stosw
mov al, Space
mov cx, Wid - 2
rep stosw
mov al, Vertical
stosw
pop cx
inc Which_row ; Bump to next row
call Make_new_ptr ; Point to it
loop LP_1
; Do bottom row of help window
mov al, Lower_left
stosw
mov al, Horizontal
mov cx, Wid - 2
rep stosw
mov al, Lower_right
stosw
mov ax, (100h * Help_window_top) + Help_window_left ; New position
mov Our_cursor, ax ; Set it for Put_Screen
ret
; Set up a pointer to this row
PUBLIC Make_new_ptr
Make_new_ptr:
push ax ; Save reg
mov ax, Which_row ; Row number of topmost row
mov bh, 2 * Number_of_columns ; Convert to bytes
mul bh
add ax, (2 * Help_window_left) + OFFSET Our_Image ; Point to our
; image, proper column
mov di, ax ; Set up as destination
pop ax ; Restore reg
ret ; Go use it
PUBLIC Fill_frame
Fill_frame:
cld ; Build forwards
mov ax, Help_window_top + 1 ; Row number to start writing to
mov Which_row, ax ; Save it
call Make_new_ptr ; Get a new DI
add di, 4 ; Skip over border, and another space
mov si, Current_line ; Start at current position in help text
mov cx, Len - 2 ; Number of rows to write
FIL_lp_outer:
push cx ; Save outer loop counter
mov cx, Wid - 4 ; Number of chars we can fit in a line
FIL_lp_inner:
lodsb ; Pick up the next byte
or al, al ; Check for zero
jnz FIL_inner_bot ; Char is ok, use it
dec si ; Back up to re-read the zero byte
mov al, Space ; Pad character
FIL_inner_bot:
stosb ; Store this char
inc di ; Skip attribute
loop FIL_lp_inner ; Go do another char
; End of inner loop, skip chars until we hit a zero byte
FIL_end_of_inner:
lodsb ; Pick up the next byte
or al, al ; Is it zero?
jnz FIL_end_of_inner ; Skip chars until we hit a zero
inc Which_row ; Move to next row
call Make_new_ptr ; Get a new DI
add di, 4 ; Skip over border and first column
pop cx ; Restore outer loop counter
loop FIL_lp_outer ; Go try for another line
ret
PUBLIC Check_keystrokes
Check_keystrokes:
call Back_to_normal_ds
call Do_mode_line ; Update the mode line
call Use_our_own_ds
mov di, OFFSET Our_image + (24 * 160) ; Where our copy is
mov cx, Number_of_columns ; Size of mode line
lds si, Mode_line_ptr ; Point to real mode line
ASSUME ds:Nothing
cld ; Forwards
rep movsw ; Copy the mode line to our buffer
push es ; Restore ds
pop ds
ASSUME ds:HAlloc
call Do_the_screen ; Install image
mov ah, 1 ; Code to see if a char is ready
int Kb ; Have BIOS tell us
jz Check_keystrokes ; None, waste time on mode line
sub ah, ah ; Zero is code to read the char
int Kb ; Have BIOS get it for us
call Back_to_normal_ds ; Check_Table requires normal ds
mov al, ah ; Copy scan code to al
mov bx, OFFSET Actions ; Action table
mov cx, N_Characters ; Number of scan codes to check
mov dx, OFFSET Characters ; The character table
jmp Check_Table ; Go dispatch to the right routine
PUBLIC Do_the_screen, Do_boop
Do_the_screen:
mov bx, OFFSET Our_Image ; Set ptr to our screen
mov ax, Normal_ds ; Put_Screen likes normal ds
mov ds, ax
ASSUME ds:DataS
or Screen_flags, Screen_changed ; Flag that Put_Screen has to work
call Put_Screen ; Update screen
push es ; Reset ds
pop ds
ASSUME ds:HAlloc
ret ; Done here
Do_boop:
call Back_to_normal_ds ; Boop requires this
call Boop ; Give low beep
call Use_our_own_ds ; Ours again
jmp Check_keystrokes ; Try again
Do_Home:
call Use_our_own_ds ; Ours again
mov di, First_line ; Button to go to first line
cmp di, Current_line ; Are we on it already?
je Do_boop ; Yeah, complain for consistency
mov Current_line, di ; Otherwise, go to first line
ret
Do_End: call Use_our_own_ds ; Ours again
mov di, Last_top_line ; Button to go to last frame line
cmp di, Current_line ; Are we on it already?
je Do_boop ; Yeah, complain for consistency
mov Current_line, di ; Otherwise, go to it
ret
Do_PgUp:
call Use_our_own_ds ; Ours again
mov di, Current_line ; Line we are on
cmp di, First_line ; First line we can be on
je Do_boop ; Can't go up
mov cx, Len - 3 ; Maximum number of lines to move
jmp SHORT PgUp_lp
Do_PgDn:
call Use_our_own_ds ; Ours again
mov di, Current_line ; Line we are on
cmp di, Last_line ; Last line we can be on
je Do_boop ; Can't go down
mov cx, Len - 3 ; Maximum number of lines to move
jmp SHORT PgDn_lp
Do_Up: call Use_our_own_ds ; Ours again
mov di, Current_line ; Line we are on
cmp di, First_line ; First line we can be on
je Do_boop ; Can't go up
jmp SHORT Up
Do_Down:
call Use_our_own_ds ; Ours again
mov di, Current_line ; Line we are on
cmp di, Last_line ; Last line we can be on
je Do_boop ; Can't go down
jmp SHORT Down
CHK_bye:
call Use_our_own_ds ; Ours again
or HFlags, Bye_bye ; Flag the exit
ret ; Done here
PgUp_lp:
push cx ; Other routine clobbers this
call Up ; Try to move up
mov di, Current_line ; Line we are on
cmp di, First_line ; First line we can be on
je CHK_pop ; Can't go up, pop reg and return
pop cx ; Restore reg
loop PgUp_lp ; Do the rest
ret ; Done here
PgDn_lp:
push cx ; Other routine clobbers this
call Down ; Try to move down
mov di, Current_line ; Line we are on
cmp di, Last_line ; Last line we can be on
je CHK_pop ; Can't go up, pop reg and return
pop cx ; Restore reg
loop PgDn_lp ; Do the rest
ret ; Done here
Down: mov cx, 80 ; Max number of chars to scan
sub al, al ; Make a zero
cld ; Forwards
repne scasb ; Go looking for a zero byte
mov Current_line, di ; Now pointing to beginning of next line
ret
Up: sub di, 2 ; Skip back over terminator
mov cx, 80 ; Max number of chars to scan
sub al, al ; Make a zero
std ; Backwards
repne scasb ; Go looking for a zero byte
add di, 2 ; Skip forwards over terminator
mov Current_line, di ; Now pointing to beginning of previous line
ret
CHK_pop:
pop cx ; Restore reg
ret
Back_to_normal_ds:
push ax ; Save reg
mov ax, Normal_ds ; Pick up addr of DataS segment
mov ds, ax ; Copy to ds
mov es, ax ; and es
pop ax ; Restore reg
ret ; and return
ASSUME ds:DataS, es:DataS
Use_our_own_ds:
push ax ; Save reg
mov ax, HAlloc_ptr ; Pick up addr of HAlloc segment
mov ds, ax ; Copy to ds
mov es, ax ; and es
pop ax ; Restore reg
ret ; and return
Helper ENDP
Do_mode_line_error PROC
call Save_mode_line ; Ask for a save
call PutErr_PC ; Play with mode line
call Bombed ; Make noise
sub ah, ah ; Code to read a character
int Kb ; Wait until user hits key
jmp Restore_mode_line ; Ask for a restore, ret from there
Do_mode_line_error ENDP
; Save the mode line for later restoral
Save_mode_line PROC
push ds ; Save ds
call Get_address ; Get new ds into ax
mov ds, ax ; Store the new seg addr
mov si, (Number_of_rows_PC-1)*2*Number_of_columns ; Offset of line 25
mov di, OFFSET Saved_mode_line ; Where to copy it
mov cx, Number_of_columns
cld ; Forwards
rep movsw ; Save the line
pop ds ; Restore ds
ret
Save_mode_line ENDP
; Restore the mode line
Restore_mode_line PROC
push es ; Save es
call Get_address ; Get new es into ax
mov es, ax ; Store the new seg addr
mov si, OFFSET Saved_mode_line ; Where copy is
mov di, (Number_of_rows_PC-1)*2*Number_of_columns ; Offset of line 25
mov cx, Number_of_columns
cld ; Forwards
rep movsw ; Restore the line
pop es ; Restore es
ret
Restore_mode_line ENDP
; Get address of segment of currently-displayed video page
Get_address PROC
mov ax, 0B000h ; Mono, maybe
cmp Which_card, 0 ; Is it?
je Go_back ; Yes
sub bh, bh ; Zero high half of bx
mov bl, Which_page ; The page we are on in the color card
shl bx, 1 ; Double for word offset into table
mov ax, Video_page_addresses[bx] ; Pick up the address for the page
Go_back:
ret
Get_address ENDP
Code ENDS
END